package edu.hawaii.halealohacli.command;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import org.junit.Before;
import org.junit.Test;
import org.wattdepot.client.WattDepotClient;
import edu.hawaii.halealohacli.HaleAlohaCli;

/**
 * Tests SetBaseline.
 * 
 * @author Jeffrey M. Beck
 * @author Zach Tomaszewski
 */
public class TestSetBaseline {

  private SetBaseline validCmdWithDate;
  private SetBaseline validCmdNoDate;

  /**
   * Constructs a valid MonitorPower command.
   */
  @Before
  public void setUp() {
    WattDepotClient client = new WattDepotClient(HaleAlohaCli.URL);
    String[] args = { "Ilima", "2011-12-08" };
    validCmdWithDate = new SetBaseline();
    validCmdWithDate.initialize(args, client);

    String[] args2 = { "Mokihana" };
    validCmdNoDate = new SetBaseline();
    validCmdNoDate.initialize(args2, client);
  }

  /**
   * Tests that a valid object can be constructed and initialized.
   */
  @Test
  public void testMakeInstance() {
    assertEquals("Command Name", validCmdWithDate.getCommandName(), "set-baseline");
    assertEquals("Command Name", validCmdNoDate.getCommandName(), "set-baseline");
  }

  /**
   * Tests that various error messages are produced when this command is
   * initialized with illegal arguments.
   */
  @Test
  public void testIllegalArguments() {
    SetBaseline cmd = new SetBaseline();
    WattDepotClient client = new WattDepotClient(HaleAlohaCli.URL);
    String[] validArgs = { "Lehua", "2011-12-09" };

    cmd.initialize(null, client);
    assertTrue("Null args detected", cmd.getResults().contains("valid arguments"));
    cmd.initialize(new String[0], client);
    assertTrue("Insufficient args detected", cmd.getResults().contains("valid arguments"));    
    cmd.initialize(new String[3], client);
    assertTrue("Extra args detected", cmd.getResults().contains("valid arguments"));    

    cmd.initialize(validArgs, null);
    assertTrue("Bad client detected", cmd.getResults().contains("client"));
    cmd.initialize(new String[]{null, "2011-12-08"}, client);
    assertTrue("Missing source name detected", cmd.getResults().contains("name"));
    cmd.initialize(new String[]{"mySource", "0"}, client);
    assertTrue("Bad date format", cmd.getResults().contains("Invalid arguments"));
  }
  
  /**
   * Tests SetBaseline's output.
   */
@org.junit.Ignore  @Test
  public void testOutputLine() {
    String line = validCmdWithDate.getResults();
    String[] tokens = line.split("\\s+");

    // Extract the energy values and test if they are all not zero.
    for (int i = 10; i <= tokens.length; i += 3) {
      // System.out.println(i + " " + tokens[i] + "\n");
      assertTrue("value > 0", Double.valueOf(tokens[i]) > 0);
    }

    // Prove there are 24 energy values
    int resultCount = 0;
    for (int i = 10; i <= tokens.length; i += 3) {
      resultCount++;
    }
    assertEquals("24 results", 24, resultCount);

    // Prove two values added together are greater than one.
    assertTrue("two values are greater than one alone",
        Double.valueOf(tokens[10]) + Double.valueOf(tokens[13]) > Double.valueOf(tokens[10]));

    /** Run the same tests above, but with no date argument given to the command. **/
    line = validCmdNoDate.getResults();
    tokens = line.split("\\s+");

    // Extract the energy values and test if they are all not zero.
    for (int i = 10; i <= tokens.length; i += 3) {
      // System.out.println(i + " " + tokens[i] + "\n");
      assertTrue("value > 0", Double.valueOf(tokens[i]) > 0);
    }

    // Prove there are 24 energy values
    resultCount = 0;
    for (int i = 10; i <= tokens.length; i += 3) {
      resultCount++;
    }
    assertEquals("24 results", 24, resultCount);

    // Prove two values added together are greater than one.
    assertTrue("two values are greater than one alone",
        Double.valueOf(tokens[10]) + Double.valueOf(tokens[13]) > Double.valueOf(tokens[10]));
  }

  /**
   * Tests the normal use of the baseline storage system.
   */
  @Test
  @SuppressWarnings("static-access")
  public void testStorage() {

    final String source = "test";
    assertFalse("Not added yet", SetBaseline.isSet(source));

    // test that set and get work, even if performed across different instances
    double[] testData = new double[24]; // all 0s
    new SetBaseline().setBaseline(source, testData);
    assertTrue("value appears to be set now", SetBaseline.isSet(source));
    assertSame("Retrieved same array inserted", testData, new SetBaseline().getBaseline(source));

    // returning to normal static syntax
    SetBaseline.setBaseline(source, new double[24]);
    assertNotSame("Setting the same source overwrites old data", testData,
        SetBaseline.getBaseline(source));
  }

  /**
   * SetBaseline's storage system should throw an exception if accessing data for a source that
   * hasn't been set yet.
   */
  @Test(expected = IllegalArgumentException.class)
  public void testStorageAccessingUnsetElement() {
    // not set yet
    SetBaseline.getBaseline("neverSet");
  }

  /**
   * Tests that all arrays added to storage are a valid length.
   */
  @Test(expected = IllegalArgumentException.class)
  public void testStorageIllegalInput() {
    // not set yet
    SetBaseline.setBaseline("test", new double[25]);
  }
}
